/**
 * @copyright 2018 sinping.com 北京芯平科技股份有限公司. All rights reserved.
 * 本内容仅限于北京芯平科技股份有限公司内部传阅，禁止外泄以及用于其他的商业目的.
 */
package com.sinping.qh.service.auth.impl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.google.common.cache.Cache;
import com.sinping.qh.api.support.Const;
import com.sinping.qh.domain.auth.Resource;
import com.sinping.qh.domain.auth.Token;
import com.sinping.qh.dto.auth.OnlineUserDTO;
import com.sinping.qh.dto.auth.UserSessionDTO;
import com.sinping.qh.utils.mapper.BeanMapper;
import com.sinping.qh.utils.mapper.JsonMapper;
import com.sinping.qh.domain.auth.User;
import com.sinping.qh.service.auth.IResourceService;
import com.sinping.qh.service.auth.ISessionService;
import com.sinping.qh.service.auth.ITokenService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentMap;

/**
 * guava 缓存实现
 *
 * @author guojie
 * @create 2018/1/3
 */
@Service
@ConditionalOnProperty(name="wn.session.cache", havingValue="guava")
public class SessionServiceGuavaImpl implements ISessionService {
    private final static Logger logger = LoggerFactory.getLogger(SessionServiceGuavaImpl.class);


    @Autowired
    private ITokenService iTokenService;

    @Autowired
    private IResourceService resourceService;
    @Autowired
    private Cache<String, String> cache;


    @Override
    public UserSessionDTO createSessionByToken(String token, User user) {
        UserSessionDTO sessionDto = new UserSessionDTO();

        if (StringUtils.isBlank(token) || user == null) {
            return sessionDto;
        }
        sessionDto.setId(user.getId());
        sessionDto.setToken(token);
        sessionDto.setNickname(user.getNickname());
        sessionDto.setUsername(user.getUsername());
        List<Resource> resources = resourceService.getResourceByUserId(user.getId());
        if (resources == null) {
            return sessionDto;
        }
        Map<String, String[]> urlMap = this.getUrlResourceAndPermission(resources);
        if (urlMap.isEmpty()) {
            return sessionDto;
        }
        // 处理 url 和 值的 内容
        sessionDto.setUrlResoure(urlMap);

        return sessionDto;
    }


    @Override
    public UserSessionDTO getSessionByToken(String token) {

        if (token != null && !"".equals(token.trim())) {

            try {
                String s=cache.getIfPresent(Const.tokenPrefix + token);
                UserSessionDTO userSessionDto = JsonMapper.defaultMapper().fromJson(s, UserSessionDTO.class);
                return userSessionDto;
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                return null;
            }
        }
        return null;

    }

    @Override
    public Long deleteSessionByToken(String token) {
        if (token != null && !"".equals(token.trim())) {
            try {
                cache.invalidate(Const.tokenPrefix + token);
                String ifPresent = cache.getIfPresent(Const.tokenPrefix + token);
                if (StringUtils.isBlank(ifPresent)) {
                    // 删除  数据库 数据
                    EntityWrapper<Token> tokenEntityWrapper = new EntityWrapper<Token>();
                    tokenEntityWrapper.where("token = {0} ", token.trim());
                    boolean delete = iTokenService.delete(tokenEntityWrapper);
                    if (delete) {
                        return 1L;
                    } else {
                        return 0L;
                    }
                }
                return 0l;
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
            }
        }
        return 0l;

    }

    @Override
    public int saveSessionToRedis(UserSessionDTO userSessionDto) {
        if (userSessionDto != null && userSessionDto.getToken() != null && !"".equals(userSessionDto.getToken().trim())) {
            try {
                String jsonStr = JsonMapper.defaultMapper().toJson(userSessionDto);
                cache.put(Const.tokenPrefix + userSessionDto.getToken().trim().toString(),jsonStr);
                String ifPresent = cache.getIfPresent(Const.tokenPrefix + userSessionDto.getToken().trim().toString());
                if(StringUtils.isNotBlank(ifPresent)){
                    return 1;
                }else{
                    return 0;
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                return 1;
            }
        }
        return 0;
    }

    @Override
    public Map<String, String[]> getUrlResourceAndPermission(List<Resource> resources) {
        {
            Map<String, String[]> urlMap = new HashMap<String, String[]>();
            try {
                for (Resource r : resources) {
                    String[] urlArr = r.getUrl().split("/");
                    //  防止资源定义  不是定义格式 /lv1/lv2/lv3
                    if (urlArr.length < 3) {
                        continue;
                    }
                    String urlStr = r.getUrl();
                    if (r.getUrl() != null && !"".equals(r.getUrl())) {
                        if (urlMap.containsKey(urlStr)) {
                            //之前处理过
                            String[] strings = urlMap.get(urlStr);
                            List<String> strings1 = new ArrayList<>();
                            for (String s : strings) {
                                strings1.add(s);
                            }
                            if (r.getRequestType() != null && !"".equals(r.getRequestType().trim()) && !strings1.contains(r.getRequestType().trim())) {
                                String requestType = r.getRequestType().trim();
                                strings1.add(requestType);
                                String[] arr = (String[]) strings1.toArray(new String[strings1.size()]);
                                urlMap.put(urlStr, arr);
                            }
                        } else {
                            if (r.getRequestType() != null && !"".equals(r.getRequestType().trim())) {
                                //新增
                                String[] requestType = {r.getRequestType().trim()};
                                urlMap.put(urlStr, requestType);
                            }
                        }
                    }
                }
            } catch (Exception e) {
                logger.error(e.getMessage(), e);
                urlMap = null;
            }
            return urlMap;
        }
    }

    @Override
    public List<OnlineUserDTO> selectOnlineUser() {
        List<OnlineUserDTO> listOnlineDTO = new ArrayList<OnlineUserDTO>();
        try{
            Set<String> keys = this.getPrefixKeys(Const.tokenPrefix);
            if (keys == null || keys.isEmpty()) {
                return listOnlineDTO;
            }
            for (Iterator it = keys.iterator(); it.hasNext(); ) {
                String key = it.next().toString();
                String value = cache.getIfPresent(key);
                if (StringUtils.isNotBlank(value)) {
                    try {
                        UserSessionDTO userSessionDTO = JsonMapper.defaultMapper().fromJson(value, UserSessionDTO.class);
                        OnlineUserDTO onlineUserDTO = BeanMapper.map(userSessionDTO, OnlineUserDTO.class);
                        listOnlineDTO.add(onlineUserDTO);
                    } catch (Exception e) {
                        logger.error("json转换实体或DTO转换失败", e);
                    }
                }
            }
        }
        catch (Exception e) {
            logger.error("Redis资源获取失败", e);
            return listOnlineDTO;
        }
        return listOnlineDTO;
    }

    @Override
    public Long deleteSessionAndTokenByUserid(String userid) {

        EntityWrapper<Token> tokenEntityWrapper = new EntityWrapper<Token>();
        Token token = new Token();
        token.setUserId(userid);
        tokenEntityWrapper.setEntity(token);
        Token token1 = iTokenService.selectOne(tokenEntityWrapper);
        if (token1 != null && token1.getToken() != null) {
            return this.deleteSessionByToken(token1.getToken());
        } else {
            return 0l;
        }

    }

    /**
     * 根据前缀获取 所用 token
     * @param prefix
     * @return
     */
    private Set<String> getPrefixKeys(String prefix){
        HashSet<String> returnSet = new HashSet<>();
        if(StringUtils.isBlank(prefix)) {
            return returnSet;
        }
        ConcurrentMap<String, String> stringStringConcurrentMap = cache.asMap();
        Set<String> keySet = stringStringConcurrentMap.keySet();
        if(keySet!=null&&!keySet.isEmpty()){
            for(String set:keySet){
             if(set.startsWith(prefix)){
                 returnSet.add(set);
             }
            }
        }
        return returnSet;
    }
}